package thesis.filesharing.web.controller;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.servlet.ModelAndView;

import thesis.filesharing.bo.ClassBO;
import thesis.filesharing.bo.ExerciseBO;
import thesis.filesharing.bo.ExerciseFileBO;
import thesis.filesharing.bo.GroupBO;
import thesis.filesharing.bo.SemesterBO;
import thesis.filesharing.bo.StudentBO;
import thesis.filesharing.common.util.XMLUtil;
import thesis.filesharing.common.valueobjects.SearchClassValueObject;
import thesis.filesharing.model.Clazz;
import thesis.filesharing.model.Exercise;
import thesis.filesharing.model.ExerciseFile;
import thesis.filesharing.model.Group;
import thesis.filesharing.resources.Constants;
import thesis.filesharing.web.auth.AuthUtil;
import thesis.filesharing.web.util.PropertiesUtil;
import thesis.filesharing.web.validator.CreateExerciseValidator;
import thesis.filesharing.web.viewmodel.CreateExerciseViewModel;
import thesis.filesharing.web.viewmodel.ExerciseViewModel;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.Text;

@Controller
public class ExerciseController {
	
	@Autowired
	private StudentBO studentBO;
	
	@Autowired
	private ExerciseBO exerciseBO;
	
	@Autowired
	private GroupBO groupBO;
	
	@Autowired
	private ClassBO classBO;
	
	@Autowired
	private ExerciseFileBO exerciseFileBO;
	
	@Autowired
	private SemesterBO semesterBO;
	
	@Autowired
	private CreateExerciseValidator createExerciseValidator;
	
	List<String> exerciseTypeNames = XMLUtil.readDataNodes(Constants.EXERCISETYPES_FILE_PATH, "exercise-type");
	List<String> workByNames = XMLUtil.readDataNodes(Constants.WORKBY_FILE_PATH, "work");
	
	@PreAuthorize("hasRole('ROLE_LECTURER')")
	@RequestMapping(value = "/lecturer/createExercise", method = RequestMethod.GET)
	public String initCreateExerciseForm(ModelMap model) {
		CreateExerciseViewModel createExerciseViewModel = new CreateExerciseViewModel();
		model.addAttribute("createExerciseViewModel", createExerciseViewModel);
		return "lecturer/createExercise";
	}
	
	@ModelAttribute("exerciseTypes")
	public Map<String, String> populateExerciseTypes() {
		Map<String, String> exerciseTypes = new LinkedHashMap<String, String>();
		for (int i = 0; i < exerciseTypeNames.size(); i++) {
			exerciseTypes.put(String.valueOf(i), exerciseTypeNames.get(i));
		}
		return exerciseTypes;
	}
	
	@ModelAttribute("groupExercises")
	public Map<String, String> populateGroupExercises() {
		Map<String, String> groupExercises = new LinkedHashMap<String, String>();
		for (int i = 0; i < workByNames.size(); i++) {
			groupExercises.put(String.valueOf(i), workByNames.get(i));
		}
		return groupExercises;
	}
	
	@ModelAttribute("classes")
	public Map<String, String> populateClasses() {
		String lecturerId = AuthUtil.getCurrentAuthenticatedUsername();
		Integer semester = semesterBO.getCurrentSemester().getSemesterName();
		List<Clazz> list = classBO.searchClasses(new SearchClassValueObject(null, null, lecturerId, semester));
		Map<String, String> classes = new LinkedHashMap<String, String>();
		for (Clazz c : list) {
			classes.put(KeyFactory.keyToString(c.getClassKey()), c.getClassId() + " - " + c.getClassName());
		}
		return classes;
	}
	
	@PreAuthorize("hasRole('ROLE_LECTURER')")
	@RequestMapping(value = "/lecturer/createExercise", method = RequestMethod.POST)
	public ModelAndView processCreateExerciseSubmit(
			@ModelAttribute("createExerciseViewModel") CreateExerciseViewModel createExerciseViewModel, 
			BindingResult bindingResult, SessionStatus status, ModelMap model, HttpSession session) {
		
		createExerciseValidator.validate(createExerciseViewModel, bindingResult);
		
		if (bindingResult.hasErrors()) {
			return new ModelAndView("lecturer/createExercise");
		} else {
			status.setComplete();
			
			Boolean isGroup = "1".equals(createExerciseViewModel.getGroupExercise());
			String exerciseType = exerciseTypeNames.get(Integer.parseInt(createExerciseViewModel.getExerciseType()));
			String[] tagList = createExerciseViewModel.getTags().split(",");
			List<String> tags = new ArrayList<String>();
			for (String s : tagList) {
				s = s.trim();
				if (!"".equals(s)) {
					tags.add(s);
				}
			}
			
			Exercise exercise = new Exercise(createExerciseViewModel.getExerciseTitle(), 
					new Text(createExerciseViewModel.getExerciseContent()), new Date(), 
					createExerciseViewModel.getDeadline(), isGroup, exerciseType, null);
			
			exerciseBO.saveExercise(exercise, createExerciseViewModel.getClassKey(), tags);
			session.setAttribute("msg", PropertiesUtil.getProperty("exercise.create.success"));
			
			return new ModelAndView();
		}
	}
	
	@InitBinder
	protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
		SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
		binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
	}
	
	@PreAuthorize("hasRole('ROLE_STUDENT')")
	@RequestMapping(value = "/student/listExercises", method = RequestMethod.GET)
	public String listExercises(@RequestParam(value = "key", required = false, defaultValue = "NONE") String classKey, ModelMap model) {
		String studentId = AuthUtil.getCurrentAuthenticatedUsername();
		if (studentId != null) {
			model.addAttribute("registeredClasses", studentBO.listClassesStudentRegistered(studentId, semesterBO.getCurrentSemester().getSemesterName()));
		}
		if (classKey != null && !"NONE".equalsIgnoreCase(classKey)) {
			Key studentKey = studentBO.findStudentById(studentId).getStudentKey();
			boolean haveGroup = groupBO.findGroupStudentRegisteredInClass(studentKey, classKey) != null;
			model.addAttribute("haveGroup", haveGroup);
			
			List<Exercise> homeWorks = exerciseBO.listExercisesOfClass(KeyFactory.stringToKey(classKey), exerciseTypeNames.get(0));
			List<Exercise> assignments = exerciseBO.listExercisesOfClass(KeyFactory.stringToKey(classKey), exerciseTypeNames.get(1));
			List<ExerciseViewModel> homeworkList = new ArrayList<ExerciseViewModel>();
			List<ExerciseViewModel> assignmentList = new ArrayList<ExerciseViewModel>();
			Key clazzKey = KeyFactory.stringToKey(classKey);
			Date uploadDate = null;
			List<ExerciseFile> exerciseFiles = null;
			
			if (homeWorks != null && !homeWorks.isEmpty()) {
				for (Exercise e : homeWorks) {
					exerciseFiles = exerciseFileBO.listExerciseFilesStudentOrGroupUploadedPerExercise(e.getExerciseKey(), studentKey, clazzKey);
					if (exerciseFiles != null && !exerciseFiles.isEmpty()) {
						uploadDate = exerciseFiles.get(0).getUploadDate();
					} else {
						uploadDate = null;
					}
					homeworkList.add(new ExerciseViewModel(e, uploadDate));
				}
			}
			
			if (assignments != null && !assignments.isEmpty()) {
				for (Exercise e : assignments) {
					exerciseFiles = exerciseFileBO.listExerciseFilesStudentOrGroupUploadedPerExercise(e.getExerciseKey(), studentKey, clazzKey);
					if (exerciseFiles != null && !exerciseFiles.isEmpty()) {
						uploadDate = exerciseFiles.get(0).getUploadDate();
					} else {
						uploadDate = null;
					}
					assignmentList.add(new ExerciseViewModel(e, uploadDate));
				}
			}
			model.addAttribute("homeWorks", homeworkList);
			model.addAttribute("assignments", assignmentList);
		}
		return "student/listExercises";
	}
	
	@PreAuthorize("hasRole('ROLE_STUDENT')")
	@RequestMapping(value = "/student/viewExercise", method = RequestMethod.GET)
	public String viewExercise(@RequestParam(value = "key", required = true) String key, ModelMap model) {
		Exercise exercise = exerciseBO.findExerciseById(KeyFactory.stringToKey(key));
		model.addAttribute("exercise", exercise);
		return "student/viewExercise";
	}
}
